package com.ld.shieldsb.common.core.reflect;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.common.core.util.TypeUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 需要java8支持
 * 
 * @ClassName FunctionUtil
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2019年7月24日 下午5:53:49
 *
 */
@Slf4j
public class FunctionUtil {
    public static boolean queryLambdasSupport = TypeUtil.isGeJdk8(); // 是否是java8以上，lambda表达式需要java8以上
    private static final Map<Property<?, ?>, String> FUNCTION_NAMES = new HashMap<>(); // Property和字段名称的对应缓存

    // 序列化以便取R的名称（即方法名）
    public interface Property<T, R> extends Function<T, R>, Serializable {
    }

    /**
     * 获取Function的名称
     * 
     * @Title getFunctionName
     * @author 吕凯
     * @date 2019年7月1日 上午11:10:44
     * @param property
     * @return String
     */
    public static String getFunctionName(Property<?, ?> property) {
        String attr = null;
        if (queryLambdasSupport) {
            attr = FUNCTION_NAMES.get(property);
            if (attr == null) {
                try {
                    Method declaredMethod = property.getClass().getDeclaredMethod("writeReplace"); // 此方法只有序列化对象有
                    declaredMethod.setAccessible(Boolean.TRUE);
                    SerializedLambda serializedLambda = (SerializedLambda) declaredMethod.invoke(property);
                    String method = serializedLambda.getImplMethodName();
                    attr = null;
                    if (method.startsWith("is")) { // is开头的
                        attr = method.substring(2);
                    } else { // get、has开头的
                        attr = method.substring(3);
                    }
                    attr = StringUtils.uncap(attr); // 首字母转小写
                    FUNCTION_NAMES.put(property, attr);
                    return attr;
                } catch (ReflectiveOperationException e) {
                    throw new RuntimeException(e);
                }
            }
        } else {
            log.warn("需要Java8以上");
        }
        return attr;

    }

}
